/**
 * 暴露的api
 * @setStorage  功能【设置storage】  参数【key：字段名 value：值 expire：过期时间】 返回【无】
 * @getStorage  功能【获取storage】  参数【key：字段名】 返回【value值，过期和null时返回null】
 * @getStorageAll 功能【获取所有storage】 参数【key：prefix 非必填，传true返回设置了前缀的storage】 返回【storage数组】
 * @hasStorage 功能【是否存在storage】参数【key：字段名】返回【storage数组】
 * @removeStorage 功能【删除storage】参数【key：字段名】返回【无】
 * @clearStorage 功能【删除所有storage】参数【key：无】返回【无】
 */
type Config = {
  type: string
  prefix: string
  isEncrypt: boolean
  expire: number
  renewalExpire: number
}

const config: Config = {
  type: 'localStorage', // 本地存储类型 localStorage/sessionStorage
  prefix: 'zcgl', // 名称前缀 建议：项目名 + 项目版本
  isEncrypt: true, // 默认加密
  expire: 0, //默认超时时间(秒)，设置默认超时时间后storage会自动超时,若不需要自动过期设置0
  renewalExpire: 60 //自动续期时间，设置的话自动续期,不设置则不会续期
}
// 引入 crypto-js
import CryptoJS from 'crypto-js'
// 十六位十六进制数作为密钥
const SECRET_KEY = CryptoJS.enc.Utf8.parse('e77ddca3bb474c9d')
// 十六位十六进制数作为密钥偏移量
const SECRET_IV = CryptoJS.enc.Utf8.parse('27a853d2d7064dfb')

/**
 * 加密方法
 * @param data
 * @returns {string}
 */
export function encrypt(data: any) {
  if (typeof data === 'object') {
    try {
      data = JSON.stringify(data) as any
    } catch (error) {
      console.log('encrypt error:', error)
    }
  }
  const dataHex = CryptoJS.enc.Utf8.parse(data)
  const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
    iv: SECRET_IV,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  })
  return encrypted.ciphertext.toString()
}
/**
 * 解密方法
 * @param data
 * @returns {string}
 */
export function decrypt(data: any, key: string) {
  const encryptedHexStr = CryptoJS.enc.Hex.parse(data)
  const str = CryptoJS.enc.Base64.stringify(encryptedHexStr)
  const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
    iv: SECRET_IV,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  })
  let decryptedStr
  try {
    decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
  } catch (e) {
    removeStorage(key)
    decryptedStr = null
  }
  return decryptedStr
    ? decryptedStr.toString()
    : JSON.stringify({
        value: ''
      })
}

// 名称前自动添加前缀
const autoAddPrefix = (key: string) => {
  const prefix = config.prefix ? config.prefix + '_' : ''
  return prefix + key
}

const autoDelPrefix = (key: string) => {
  return config.prefix ? key.replace(config.prefix + '_', '') : ''
}

export const setStorage = (key: string, value: any, expire?: number) => {
  console.log('setStorage', key, value)
  // 判断空状态忽略 0 NaN false
  if (value === '' || value === null || value === undefined) {
    value = null
  }

  if (expire && (isNaN(expire) || expire < 1))
    throw new Error('过期时间必须是大于1的数字！')

  const newExpire = expire
    ? expire * 1000
    : config.expire
    ? config.expire * 1000
    : null
  const data = {
    value: value, // 存储值
    time: Date.now(), //存值时间戳
    expire: newExpire // 过期时间
  }
  // 对存储数据进行加密 加密为可选配置
  const encryptString = config.isEncrypt
    ? encrypt(JSON.stringify(data))
    : JSON.stringify(data)
  window[config.type].setItem(autoAddPrefix(key), encryptString)
}
// 获取 getStorage
export const getStorage = (key: string) => {
  // key 不存在判断
  if (
    !window[config.type].getItem(autoAddPrefix(key)) ||
    JSON.stringify(window[config.type].getItem(autoAddPrefix(key))) === 'null'
  ) {
    return null
  }

  //获取值
  let storage
  if (config.isEncrypt) {
    const decryptData = decrypt(
      window[config.type].getItem(autoAddPrefix(key)),
      autoAddPrefix(key)
    )
    const parseData =
      decryptData && typeof decryptData === 'string'
        ? JSON.parse(decryptData)
        : { value: '' }
    storage =
      parseData && typeof parseData === 'object' ? parseData : { value: '' }
  } else {
    storage = JSON.parse(window[config.type].getItem(autoAddPrefix(key)))
  }

  const time = storage.time
  const expire = storage.expire
  //未设置过期时间，直接返回结果
  if (!expire) {
    return storage.value
  }
  //设置了过期时间↓↓↓
  const nowTime = Date.now()
  // 过期删除
  if (nowTime - time > expire) {
    removeStorage(key)
    return null
  } else {
    // @Todo: 暂时去掉退出登录缓存保活
    // 未过期期间被调用 则自动续期 进行保活
    // if (config.renewalExpire) {
    //   setStorage(key, storage.value, config.renewalExpire)
    //   return storage.value
    // }
  }
}

// 获取全部 getAllStorage
export const getStorageAll = (key?: boolean) => {
  const len = window[config.type as any].length // 获取长度
  const arr: { key: string; val: any }[] = [] // 定义数据集
  for (let i = 0; i < len; i++) {
    // 获取key 索引从0开始
    // @ts-ignoreS
    const getKey = window[config.type].key(i)
    // 获取key对应的值
    // @ts-ignore
    const getVal = window[config.type].getItem(getKey)
    // 放进数组
    if (key) {
      getKey.includes(config.prefix) &&
        arr.push({ key: autoDelPrefix(getKey), val: getVal })
    } else {
      arr.push({ key: autoDelPrefix(getKey), val: getVal })
    }
  }

  return arr
}

// 是否存在 hasStorage
export const hasStorage = (key: string) => {
  // key = autoAddPrefix(key);
  const arr = getStorageAll().filter((item) => {
    return item.key === key
  })
  return !!arr.length
}

// 删除 removeStorage
export const removeStorage = (key: string) => {
  // @ts-ignore
  window[config.type].removeItem(autoAddPrefix(key))
}

// 清空 clearStorage
export const clearStorage = () => {
  // @ts-ignore
  window[config.type].clear()
}

// export default {
//   setStorage,
//   getStorage,
//   hasStorage,
//   clearStorage,
//   getStorageAll,
//   removeStorage
// }
